﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Data;
using System.Linq.Expressions;
using Framework.EntityFramework;

namespace Framework.DataAccess
{
    public abstract class RepositoryBase<T> where T : class
    {
        private  DomainContext _db;
        private readonly IDbSet<T> _dbset;

        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            _dbset = DomainContext.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory 
        { get;private set; }

        protected DomainContext DomainContext
        {
            get { return _db ?? (_db = DatabaseFactory.Get()); }
        }
        
        public virtual bool Add(T entity)
        {
            try
            {
                _dbset.Add(entity);                  
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
            
        }

        public virtual bool Update(T entity)
        {
            try
            {
                _dbset.Attach(entity);
                _db.Entry(entity).State = EntityState.Modified;
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }            
        }

        public virtual bool Delete(T entity)
        {
            try
            {                
                _dbset.Remove(entity);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
            
        }

        public virtual bool Delete(Expression<Func<T, bool>> where)
        {
            
            try
            {
                IEnumerable<T> objects = _dbset.Where<T>(where).AsEnumerable();
                foreach (T obj in objects)
                    _dbset.Remove(obj);
                return true;
            }
            catch (Exception)
            {
                return false;                
            }
        }

        public virtual T GetById(long id)
        {
            return _dbset.Find(id);
        }

        public virtual T GetById(int id)
        {
            return _dbset.Find(id);
        }

        public virtual T GetById(string id)
        {
            return _dbset.Find(id);
        }

        public virtual IEnumerable<T> GetAll()
        {
            return _dbset.ToList();
        }

        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where=null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<T> query = _dbset;
            if (where != null)
            {
                query = query.Where(where);
            }
            foreach (var includeProperty in includeProperties.Split(new char[]{','},StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }
            return orderBy!=null ? orderBy(query).ToList() : query.ToList();
        }

        public T Get(Expression<Func<T, bool>> where)
        {
            return _dbset.Where(where).FirstOrDefault<T>();
        }

        public void SaveChanges()
        {
            DomainContext.SaveChanges();            
        }
    }
}
